﻿using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading.Tasks;

namespace CommonDevelop.Cache.Impl
{
    /// <summary>
    /// 分布式缓存服务
    /// </summary>
    public class DCSCacheService : IDCSCache
    {
        protected IDistributedCache _cache;
        /// <summary>
        /// 构造
        /// </summary>
        public DCSCacheService(IDistributedCache cache)
        {
            this._cache = cache;
        }

        /// <summary>
        /// 添加缓存
        /// </summary>
        public bool Add(string key, object value, TimeSpan? expiresIn = null, bool isSliding = false)
        {
            if (string.IsNullOrWhiteSpace(key))
                throw new ArgumentNullException(nameof(key));

            if (value == null)
                return false;

            byte[] val = this.Serialize(value);
            if (expiresIn.HasValue)
            {
                if (isSliding)
                    _cache.Set(key, val, new DistributedCacheEntryOptions().SetSlidingExpiration(expiresIn.Value));
                else
                    _cache.Set(key, val, new DistributedCacheEntryOptions().SetAbsoluteExpiration(expiresIn.Value));
            }
            else
            {
                DistributedCacheEntryOptions options = new DistributedCacheEntryOptions();
                //设置绝对过期时间 两种写法
                options.AbsoluteExpiration = DateTime.Now.AddMinutes(30);
                // options.SetAbsoluteExpiration(DateTime.Now.AddMinutes(30));
                //设置滑动过期时间 两种写法
                options.SlidingExpiration = TimeSpan.FromSeconds(60);
                //options.SetSlidingExpiration(TimeSpan.FromSeconds(60));
                //添加缓存
                this._cache.Set(key, val, options);
            }
            //刷新缓存
            this._cache.Refresh(key);
            return this.Exists(key);
        }
        /// <summary>
        /// 验证缓存项是否存在
        /// </summary>
        public bool Exists(string key)
        {
            if (string.IsNullOrWhiteSpace(key))
                return false;

            bool ReturnBool = true;
            byte[] val = _cache.Get(key);
            if (val == null || val.Length == 0)
                ReturnBool = false;

            return ReturnBool;
        }
        /// <summary>
        /// 获取缓存
        /// </summary>
        public object Get(string key)
        {
            if (!string.IsNullOrEmpty(key))
            {
                if (this.Exists(key))
                {
                    var bt = this._cache.Get(key);
                    return this.Deserialize<object>(bt);
                }
            }
            return null;
        }
        /// <summary>
        /// 获取缓存集合
        /// </summary>
        public IDictionary<string, object> GetAll(IEnumerable<string> keys)
        {
            if (keys == null)
                throw new ArgumentNullException(nameof(keys));

            var dict = new Dictionary<string, object>();
            keys.ToList().ForEach(item =>
            {
                var obj = this.Get(item);
                if (obj != null)
                    dict.Add(item, obj);
            });
            return dict;
        }
        /// <summary>
        /// 异步获取缓存
        /// </summary>
        public async Task<T> GetAsync<T>(string key) where T : class
        {
            T ReturnObj = default(T);
            var bt = await _cache.GetAsync(key);
            if (bt != null)
                ReturnObj = this.Deserialize<T>(bt);

            return ReturnObj;
        }
        /// <summary>
        /// 删除缓存
        /// </summary>
        public bool Remove(string key)
        {
            if (string.IsNullOrWhiteSpace(key))
                return false;

            this._cache.Remove(key);
            return !this.Exists(key);
        }
        /// <summary>
        /// 批量删除缓存
        /// </summary>
        public void RemoveAll(IEnumerable<string> keys)
        {
            if (keys == null)
                throw new ArgumentNullException(nameof(keys));

            keys.ToList().ForEach(item =>
            {
                if (!string.IsNullOrWhiteSpace(item))
                    this._cache.Remove(item);
            });
        }
        /// <summary>
        /// 修改缓存
        /// </summary>
        public bool Replace(string key, object value, TimeSpan? expiresIn = null, bool isSliding = false)
        {
            if (string.IsNullOrWhiteSpace(key))
                throw new ArgumentNullException(nameof(key));

            if (value == null)
                throw new ArgumentNullException(nameof(value));

            if (this.Exists(key))
                if (!this.Remove(key))
                    return false;

            return this.Add(key, value, expiresIn, isSliding);
        }

        /// <summary>
        /// 序列化
        /// </summary>
        private byte[] Serialize(object obj)
        {
            if (obj == null)
                return null;

            var binaryFormatter = new BinaryFormatter();
            using (var memoryStream = new MemoryStream())
            {
                binaryFormatter.Serialize(memoryStream, obj);
                var data = memoryStream.ToArray();
                return data;
            }
        }

        /// <summary>
        /// 反序列化
        /// </summary>
        private T Deserialize<T>(byte[] data)
        {
            if (data == null)
                return default(T);

            var binaryFormatter = new BinaryFormatter();
            using (var memoryStream = new MemoryStream(data))
            {
                var result = (T)binaryFormatter.Deserialize(memoryStream);
                return result;
            }
        }
    }
}
